//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "gsensor.h"

CGSensor *g_pGSensor;
/*
  s_modeCount[0] GSENSOR_NONE_INT_ENABLE
  s_modeCount[1] GSENSOR_DOUBLE_TAP_ENABLE
  s_modeCount[2] GSENSOR_SHAKE_ENABLE
  s_modeCount[3] GSENSOR_RUNNER_ENABLE
*/
static Int32 s_modeCount[4] = {0};
static Int32 s_currentMode = 0;
static Int32 s_countSum = 0;

ECode ChangeGsensorMode(UInt8 mode)
{
    int ret;
    nu_GSensorUnsubscribe();
    ret = nu_GSensorSubscribe(mode, g_pGSensor->m_eCallBackMode);
    if (ret) {
        nu_GSensorUnsubscribe();
        kprintf("chang gsensor mode error\n");
        return E_ACCESS_DENIED;
    }
    nu_GSensorSetFreq(g_pGSensor->m_uFrequency);
    s_currentMode = mode;

    return NOERROR;
}

ECode FirstOpenGsensor(UInt8 mode)
{
    int ret;
    assert(g_pGSensor->m_uStart >= 1);
    if (1 == g_pGSensor->m_uStart) {
        ret = nu_GSensorSubscribe(0, g_pGSensor->m_eCallBackMode);
        nu_GSensorSetFreq(g_pGSensor->m_uFrequency);
        if (ret) {
            kprintf("---------------nu_GSensorSubscribe Error\n");
            return E_ACCESS_DENIED;
        }
    }
    return ChangeGsensorMode(mode);
}

ECode CGSensor::Read(
    /* [in] */ Int64 offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode CGSensor::Write(
    /* [in] */ Int64 offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    // TODO;
    return E_NOT_IMPLEMENTED;
}

ECode CGSensor::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = NOERROR;
    switch (nControlCode) {
        case 0:{//Open GSensor
            if(0 < m_uStart){
                m_uStart++;
                break;
            }
            int ret = nu_GSensorSubscribe(m_eEventMode, m_eCallBackMode);
            if(ret){
                ec = E_ACCESS_DENIED;
            }
            nu_GSensorSetFreq(m_uFrequency);
            m_uStart++;
            break;

        }
        case 1:{//Close GSensor
            //Not start
            if(0 == m_uStart){
                break;
            }
            //The last user
            if(1 == m_uStart){
                nu_GSensorUnsubscribe();
                m_uState = GSENSOR_NONE_INTERRUPT;
            }
            m_uStart--;
            break;

        }
        case 2:{//Get GSensor state
            if(GSENSOR_EventCallBack != m_eCallBackMode){
                return E_INVALID_ARGUMENT;
            }
            Int32 *pBuf = NULL;
            assert(NULL != (char *)pOutBuffer);
            pBuf = (Int32 *)((Byte *)pOutBuffer->GetPayload());
            pOutBuffer->SetUsed(sizeof(Int32));
            if (0 == m_uStart) {//Not start
                *pBuf = GSENSOR_NONE_INTERRUPT;
            } else if(GSENSOR_NONE_INTERRUPT == m_uState){//Just start no state
                WaitResult wr;
                EventState state;
                DzEvent event;
                *pBuf = GSENSOR_NONE_INTERRUPT;
    			m_pWaitStateEvent = &event;

//				ec = DzCreateEventObj(FALSE, UNSIGNALED, &m_pWaitStateEvent);
//                if(FAILED(ec)){
//                    kprintf("Create GSensor state event failed.\n");
//                    break;
//                }
                m_pWaitStateEvent->TryWait(200, &wr, &state);
                if(WaitResult_OK == wr){
                    *pBuf = m_uState;
                    kprintf("m_pWaitStateEvent OK m_uState:0x%x\n", m_uState);
                } else {
                    kprintf("m_pWaitStateEvent failed\n");
                }
//                m_pWaitStateEvent->Release();
                m_pWaitStateEvent = NULL;
            } else {
               *pBuf = m_uState;
            }
            break;
        }
        case 3:{//Set GSensor Callback mode

            int ret ;
            Uint32 CallBackMode;

            if ((inBuffer.GetPayload() == NULL)
                &&(inBuffer.GetCapacity() < (int)sizeof(Uint32))) {
                ec = E_INVALID_ARGUMENT;
                break;
            }
            CallBackMode = *(Uint32 *)((Byte *)inBuffer.GetPayload());

            m_eCallBackMode = (Uint8)CallBackMode;
            if(0 < m_uStart){
                nu_GSensorUnsubscribe();
                if(GSENSOR_DataCallBack == m_eCallBackMode) {
                    m_pSendFunc = SendDataFunc;
                } else {
                    m_pSendFunc = SendEventFunc;
                }
                ret = nu_GSensorSubscribe(m_eEventMode, m_eCallBackMode);
                if(ret){
                    ec = E_ACCESS_DENIED;
                }
                nu_GSensorSetFreq(m_uFrequency);
            }else{
                if(GSENSOR_DataCallBack == m_eCallBackMode) {
                    m_pSendFunc = SendDataFunc;
                } else {
                    m_pSendFunc = SendEventFunc;
                }
            }
            break;
        }
        case 4:{//Set GSensor Event mode
            int ret ;
            Uint32 Eventmode;

            if ((inBuffer.GetPayload() == NULL)
                &&(inBuffer.GetCapacity() < (int)sizeof(Uint32))) {
                ec = E_INVALID_ARGUMENT;
                break;
            }
            Eventmode = *(Uint32 *)((Byte *)inBuffer.GetPayload());

            m_eEventMode = (Uint8)Eventmode;
            if(0 < m_uStart){
                nu_GSensorUnsubscribe();
                ret = nu_GSensorSubscribe(m_eEventMode, m_eCallBackMode);
                if(ret){
                    ec = E_ACCESS_DENIED;
                }
                nu_GSensorSetFreq(m_uFrequency);
            }
            break;
        }
        case 5:{//Set GSensor frequency
            Uint32 Frequency;
            if ((inBuffer.GetPayload() == NULL)
                &&(inBuffer.GetCapacity() < (int)sizeof(Uint32))) {
                ec = E_INVALID_ARGUMENT;
                break;
            }
            Frequency = *(Uint32 *)((Byte *)inBuffer.GetPayload());

            m_uFrequency = (Uint8)Frequency;
            if(0 < m_uStart){
                nu_GSensorSetFreq(m_uFrequency);
                break;
            }
            kprintf("Set GSensor frequency OK");
            break;
        }
        case 6:{//Set GSensor Rotate type
            Uint32 Rotatetype;
            if ((inBuffer.GetPayload() == NULL)
                &&(inBuffer.GetCapacity() < (int)sizeof(Uint32))) {
                ec = E_INVALID_ARGUMENT;
                break;
            }
            Rotatetype = *(Uint32 *)((Byte *)inBuffer.GetPayload());

            m_uRotatetype = (Uint8)Rotatetype;
            nu_GSensor_SetRotate(m_uRotatetype);
            kprintf("Set GSensor Rotate type: %d OK\n", m_uRotatetype);
            break;
        }
        case 7:{//Set GSensor Sensitivity for runner mode
            Uint32 Sensitivity;
            if ((inBuffer.GetPayload() == NULL)
                &&(inBuffer.GetCapacity() < (int)sizeof(Uint32))) {
                ec = E_INVALID_ARGUMENT;
                break;
            }
            Sensitivity = *(Uint32 *)((Byte *)inBuffer.GetPayload());
            if(1 > Sensitivity){
                m_uSensitivity = 1;
            }else if(10 < Sensitivity){
                m_uSensitivity = 10;
            }else {
                m_uSensitivity = (Uint8)Sensitivity;
            }
            nu_GSensor_SetSensitivity(m_uSensitivity);
            kprintf("Set GSensor Sensitivity: %d OK\n", m_uSensitivity);
            break;
        }

        case 8: {
            if (NULL == inBuffer.GetPayload() &&
                inBuffer.GetCapacity() < (int)(sizeof(Uint32)*2)) {
                return E_INVALID_ARGUMENT;
            }
            Uint32 *p = (Uint32*)inBuffer.GetPayload();
            Uint32 eventMode = p[0];
            Uint32 onOff = p[1]; // 1 open gsensor corresponding eventMode, 0 close gsensor corresponding eventMode

            if (eventMode > GSENSOR_RUNNER_ENABLE ||
                  eventMode < GSENSOR_DOUBLE_TAP_ENABLE) {
                return E_INVALID_ARGUMENT;
            }

            if (onOff) {
                s_modeCount[eventMode]++;
                m_uStart++;
            } else {
                s_modeCount[eventMode]--;
                m_uStart--;
            }

            assert(s_modeCount[eventMode] >= 0);
            if (s_modeCount[eventMode] < 0) {
                s_modeCount[eventMode] = 0;
            }
            kprintf("-------m_uStart = %d\n", m_uStart);
            kprintf("-------s_modeCount[GSENSOR_SHAKE_ENABLE] = %d\n", s_modeCount[GSENSOR_SHAKE_ENABLE]);
            kprintf("-------s_modeCount[GSENSOR_DOUBLE_TAP_ENABLE] = %d\n", s_modeCount[GSENSOR_DOUBLE_TAP_ENABLE]);
            kprintf("-------s_modeCount[GSENSOR_RUNNER_ENABLE] = %d\n", s_modeCount[GSENSOR_RUNNER_ENABLE]);

            if (s_modeCount[GSENSOR_RUNNER_ENABLE] > 1) { //hightest priority has been used just return
                return NOERROR;
            }

            s_countSum = s_modeCount[GSENSOR_DOUBLE_TAP_ENABLE] + \
                         s_modeCount[GSENSOR_SHAKE_ENABLE] + \
                         s_modeCount[GSENSOR_RUNNER_ENABLE];

           assert(m_uStart >= 0);
           if (0 == s_countSum) { //all mode has been closed just close gsensor and return
                if (m_uStart == 0) {
                    kprintf("-----------------close gsensor\n");
                    s_currentMode = 0;
                    nu_GSensorUnsubscribe();
                } else if (m_uStart > 0){
                    kprintf("-----------------set GSENSOR_NONE_INT_ENABLE mode\n");
                    ChangeGsensorMode(GSENSOR_NONE_INT_ENABLE);
                }
                return NOERROR;
            }

            if (onOff && s_countSum == 1) { //first set gsensor mode
                assert(s_currentMode == 0);
                kprintf("---------------set mode first mode = %d\n, m_eCallBackMode = %d\n", eventMode, m_eCallBackMode);
                return FirstOpenGsensor((UInt8)eventMode);
            }

            if (s_modeCount[GSENSOR_RUNNER_ENABLE] != 0 &&
                    s_currentMode != GSENSOR_RUNNER_ENABLE) {
                kprintf("---------------set GSENSOR_RUNNER_ENABLE\n");
                return ChangeGsensorMode(GSENSOR_RUNNER_ENABLE);
            }



            if (s_modeCount[GSENSOR_DOUBLE_TAP_ENABLE] != 0 &&
                    s_modeCount[GSENSOR_RUNNER_ENABLE] == 0 &&
                    s_currentMode != GSENSOR_DOUBLE_TAP_ENABLE
                    ) {
                kprintf("---------------set GSENSOR_DOUBLE_TAP_ENABLE\n");
                return ChangeGsensorMode(GSENSOR_DOUBLE_TAP_ENABLE);
            }

            if (s_modeCount[GSENSOR_SHAKE_ENABLE] != 0 &&
                    s_modeCount[GSENSOR_DOUBLE_TAP_ENABLE] == 0 &&
                    s_modeCount[GSENSOR_RUNNER_ENABLE] == 0 &&
                    s_currentMode != GSENSOR_SHAKE_ENABLE) {
                kprintf("---------------set GSENSOR_SHAKE_ENABLE\n");
                return ChangeGsensorMode(GSENSOR_SHAKE_ENABLE);
            }
            break;
        }

        default:
            ec = E_NOT_IMPLEMENTED;
            break;
    }
    return ec;
}

void CloseSensor()
{
    if (0 != s_countSum && s_modeCount[GSENSOR_RUNNER_ENABLE] == 0) {
        nu_GSensorUnsubscribe();
    }
}

ECode RestorGsensor()
{
    if (s_modeCount[GSENSOR_RUNNER_ENABLE] == 0 && s_countSum > 0) {
        if (s_modeCount[GSENSOR_DOUBLE_TAP_ENABLE] != 0) {
            return FirstOpenGsensor(GSENSOR_DOUBLE_TAP_ENABLE);
        }
        if (s_modeCount[GSENSOR_SHAKE_ENABLE] != 0) {
            return FirstOpenGsensor(GSENSOR_SHAKE_ENABLE);
        }
    }
    return NOERROR;
}

void CGSensor::Dispose()
{
    m_pIThread->Abort();
}


void SendGSensorData(nuGSensorData &data)
{
    struct EmIsrParameter {
        Int32 nParameter1;
        Int32 nParameter2;
        Int32 nParameter3;
        Int32 nParameter4;
    };
    EmIsrParameter pParam;
    pParam.nParameter1 = 0x80000000;
    pParam.nParameter2 = data.x;
    pParam.nParameter3 = data.y;
    pParam.nParameter4 = data.z;

    MemoryBuf eventData ((Byte *)&pParam, sizeof(EmIsrParameter));

    EmPostEvent(230, eventData);
    kprintf("SendGSensorData x %d.\n", pParam.nParameter2);
    kprintf("SendGSensorData y %d.\n", pParam.nParameter3);
    kprintf("SendGSensorData z %d.\n", pParam.nParameter4);
}

void SendGSensorEvent(UInt32 GEvent)
{
    UInt32 uEvent = 0;
    MemoryBuf eventData ((Byte *)&uEvent, sizeof(UInt32));
    Uint32 uOldState = g_pGSensor->m_uState;
    uEvent = (UInt32)GEvent;

    switch(uEvent){
        case GSENSOR_ROTATE_LEFT_INTERRUPT:
            g_pGSensor->m_uState = GSENSOR_LEFT;
            break;
        case GSENSOR_ROTATE_RIGHT_INTERRUPT:
            g_pGSensor->m_uState = GSENSOR_RIGHT;
            break;
        case GSENSOR_ROTATE_UP_INTERRUPT:
            g_pGSensor->m_uState = GSENSOR_UP;
            break;
        case GSENSOR_ROTATE_DOWN_INTERRUPT:
            g_pGSensor->m_uState = GSENSOR_DOWN;
            break;
        case GSENSOR_ROTATE_TOP_INTERRUPT:
            g_pGSensor->m_uState = GSENSOR_TOP;
            break;
        case GSENSOR_ROTATE_BOTTOM_INTERRUPT:
            g_pGSensor->m_uState = GSENSOR_BOTTOM;
            break;
        default:
            break;
    }
    if ((GSENSOR_NONE_INTERRUPT != uOldState)&&(NULL != g_pGSensor->m_pWaitStateEvent)) {
        kprintf("m_pWaitStateEvent uEvent 0x%02x.\n", uEvent);
        g_pGSensor->m_pWaitStateEvent->Notify(SIGNALED);
//		DzNotifyEventObjByIsr(g_pGSensor->m_pWaitStateEvent, SIGNALED);
    }

    EmPostEvent(230, eventData);

    kprintf("SendGSensorEvent uEvent 0x%02x.\n", uEvent);
}

void SendEventFunc(void)
{
    UInt32 i;
    assert(g_pGSensor->m_uszGSensorEvent[0] > 0
        && g_pGSensor->m_uszGSensorEvent[0] < 64);
    for(i = 1; i <= g_pGSensor->m_uszGSensorEvent[0]; i++){
        if(GSENSOR_NONE_INTERRUPT == g_pGSensor->m_uszGSensorEvent[i]){
            continue;
        }
        SendGSensorEvent(g_pGSensor->m_uszGSensorEvent[i]);
    }
}

void SendDataFunc(void)
{
    UInt16 i;
    assert(g_pGSensor->m_GSensorData[0].x > 0
        && g_pGSensor->m_GSensorData[0].x < 64);
    for(i = 1; i <= g_pGSensor->m_GSensorData[0].x; i++){
        SendGSensorData(g_pGSensor->m_GSensorData[i]);
    }
}

//TODO:Add Send data func
Int32 GSensorGetEventThread(void *p)
{
    WaitResult wr;
    EventState state;
//    nu_puts("GSensorGetEventThread on!\n");

    while(1){
        g_pGSensor->m_event.Wait(&wr, &state);
        if(!g_pGSensor->m_uTakeBack){
            g_pGSensor->m_pSendFunc();
        }
        g_pGSensor->m_uTakeBack = TRUE;
    }
    return 1;
}

EXTERN IDeviceDriver * CDECL CreateGsensor(uint_t uDeviceNo, void *pvParameter)
{
    ECode ec;
    CGSensor *pGSensor = new CGSensor;
    if(NULL == pGSensor){
        nu_puts("CreateGsensor new failed!\n");
        return NULL;
    }
    g_pGSensor = pGSensor;
    pGSensor->AddRef();

    ec = DzCreateKernelThread(GSensorGetEventThread,
                              NULL,
                              CreateThreadFlag_System,
                              ThreadPriorityRank_SoftRealTime,
                              &pGSensor->m_pIThread);
    if(FAILED(ec)){
        nu_puts("CreateGsensor thread failed!\n");
        pGSensor->Release();
        g_pGSensor = NULL;
        return NULL;
    }

    nu_GSensorInit(pGSensor->m_GSensorData,
                   pGSensor->m_uszGSensorEvent,
                   &pGSensor->m_uTakeBack,
                   (Uint32)&pGSensor->m_event);
    nu_puts("Create Gsensor ok!\n");

    return (IDeviceDriver *)g_pGSensor;
}
